#ifndef TIEC_UTIL_H
#define TIEC_UTIL_H

#include <list>
#include "macro.h"
#include "data.h"
#include "foundation.h"

namespace NS_TIEC {

  class TimeUtil {
  public:
    /// 获取当前毫秒时间戳
    /// \return 毫秒时间戳
    static Int64 milliTime();

    /// 获取当前微秒时间戳
    /// \return 微秒时间戳
    static Int64 microTime();

    /// 获取当前纳秒时间戳
    /// \return 纳秒时间戳
    static Int64 nanoTime();
  private:
    TimeUtil() = delete;
    TimeUtil(const TimeUtil&) = delete;
    TimeUtil& operator=(const TimeUtil&) = delete;
  };

  /// 汉字拼音信息
  struct HanziPinyin {
    /// 所有首拼（包含多音字读音）
    List<String> firsts;
    /// 所有全拼（包含多音字读音）
    List<String> fulls;
  };

  class PinyinUtil {
  public:
    /// 获取汉字所有拼音信息（包含所有多音字全拼首拼）
    /// @param in_str 汉字
    /// @return 汉字拼音信息
    static HanziPinyin getHanziPinyin(const String& in_str);

    /// 获取汉字首拼
    /// @param in_str 汉字
    static String getHanziFirstPinyin(const String& in_str);

    /// 获取汉字全拼
    /// @param in_str 汉字
    static String getHanziFullPinyin(const String& in_str);

    /// 获取汉字全拼（小驼峰形式）
    /// @param in_str
    static String getHanziFullPinyinLowerCamel(const String& in_str);

    /// 获取汉字全拼（大驼峰形式）
    /// @param in_str 汉字
    static String getHanziFullPinyinUpperCamel(const String& in_str);
  private:
    PinyinUtil() = delete;
    PinyinUtil(const PinyinUtil&) = delete;
    PinyinUtil& operator=(const PinyinUtil&) = delete;
    static HashMap<String, HanziPinyin> pinyin_cache_;
  };

  /// 文件操作工具类
  class FileUtil {
  public:
    /// 获取指定路径文件的名称
    /// @param path 文件路径
    /// @return 文件名称（包含后缀名）
    static String getPathName(const String& path);

    /// 获取指定路径文件的扩展名
    /// @param path 文件路径
    /// @return 文件扩展名
    static String getExtension(const String& path);

    /// 获取指定路径的所处目录
    /// @param path 文件路径
    /// @return 文件目录路径
    static String getParentPath(const String& path);

    /// 判断指定路径文件是否存在
    /// @param path 文件路径
    /// @return 如果文件存在返回true
    static bool exists(const String& path);

    /// 创建文件夹(会递归创建父目录)
    /// @param path 文件夹路径
    /// @return 创建成功返回true
    static bool mkdirs(const String& path);

    /// 创建文件夹(不递归创建父目录)
    /// @param path 文件夹路径
    /// @return 创建成功返回true
    static bool mkdir(const String& path);

    /// 判断指定路径是否为文件，不是文件夹
    /// @param path 文件路径
    /// @return 如果文件存在并且不是文件夹返回true
    static bool isFile(const String& path);

    /// 判断指定路径是否为文件夹，不是文件
    /// @param path 文件路径
    /// @return 如果文件夹存在并且不是文件返回true
    static bool isDirectory(const String& path);

    /// 拷贝单个文件
    /// @param src_file 文件路径
    /// @param dst_file 目标拷贝路径
    /// @return 拷贝成功返回true
    static bool copyFile(const String& src_file, const String& dst_file);

    /// 拷贝单个文件到指定目录下
    /// @param src_file 文件路径
    /// @param dst_dir 目标目录
    /// @return 拷贝成功返回true
    static bool copyFileToDir(const String& src_file, const String& dst_dir);

    /// 拷贝整个文件夹
    /// @param src_dir 文件夹路径
    /// @param dst_dir 目标拷贝路径
    /// @return 拷贝成功返回true
    static bool copyDirectory(const String& src_dir, const String& dst_dir);

    /// 列出目录下所有文件
    /// @param dir 文件夹路径
    /// @return 返回目录下所有文件路径
    static std::list<String> listChildren(const String& dir);

    /// 遍历目录下所有文件
    /// @param dir 文件夹路径
    /// @param func 遍历函数
    static void walkDirectory(const String& dir, std::function<void(const String&)>&& func);
  private:
    FileUtil() = delete;
    FileUtil(const FileUtil&) = delete;
    FileUtil& operator=(const FileUtil&) = delete;
  };

  class FileExtensionMatcher {
  public:
    FileExtensionMatcher(const std::initializer_list<String>& extensions);
    bool match(const String& path) const;
    String description() const;
  private:
    std::unordered_set<String> extension_set_;
  };

  class StrUtil {
  public:
    /// String转换为WString
    /// \param s String内容
    /// \return 转换后的宽文本
    static std::wstring toWString(const std::string& s);

    /// WString转换为String
    /// \param ws WString内容
    /// \return 转换后的UTF8文本
    static std::string toString(const std::wstring& ws);

    /// 将宽文本转换为C风格字符串（内存安全）
    /// @param ws 宽文本
    static UPTR<const char[]> toCString(const std::wstring& ws);

    /// 整数转换为String
    /// \param n 整数
    /// \return
    static String toString(Int64 n);

    /// float转换为String
    /// \param n 整数
    /// \return
    static String toString(float n);

    /// double转换为String
    /// \param n 整数
    /// \return
    static String toString(double n);

    /// String转int32
    /// \param s 字符串
    /// \return
    static Int32 toInt32(const String& s);

    /// 16进制String转int32
    /// \param s 字符串
    /// \return
    static Int32 hexToInt32(const String& s);

    /// 8进制String转int32
    /// \param s 字符串
    /// \return
    static Int32 octToInt32(const String& s);

    /// String转int64
    /// \param s 字符串
    /// \return
    static Int64 toInt64(const String& s);

    /// 16进制String转int64
    /// \param s 字符串
    /// \return
    static Int64 hexToInt64(const String& s);

    /// 8进制String转int64
    /// \param s 字符串
    /// \return
    static Int64 octToInt64(const String& s);

    /// String转float
    /// \param s 字符串
    /// \return
    static float toFloat(const String& s);

    /// String转double
    /// \param s 字符串
    /// \return
    static double toDouble(const String& s);

    /// 接受va_list作为参数进行格式化
    /// @param format 格式
    /// @param args 参数
    /// @return 格式化之后的文本
    static String vFormatString(const char* format, va_list args);

    /// 格式化字符串
    /// \param format 格式
    /// \param ... 替换参数
    /// \return 格式化之后的文本
    static String formatString(const char* format, ...);

    /// 将文本转换为大写
    /// \param wtr 文本
    static String toUpper(const String& str);

    /// 去首尾空
    /// \param str 要去除首尾空的文本
    static String trim(const String& str);

    /// 处理转义字符
    static String unescape(const String& str);

    /// 替换文本中指定的第一个文本为另一个文本
    /// @param str 原始文本
    /// @param from 要替换的文本
    /// @param to 替换后文本
    /// @return 替换成功返回true
    static bool replaceFirst(String& str, const String& from, const String& to);

    /// 替换文本中指定文本为另一个文本（全部替换）
    /// @param source 原始文本
    /// @param from 要替换的文本
    /// @param to 替换后文本
    /// @return 替换成功返回true
    static String replaceAll(const String& source, const String& from, const String& to);

    /// 判断文本开头是否为指定文本
    /// @param str 文本
    /// @param prefix 前缀
    static bool startsWith(const String& str, const String& prefix);

    /// 判断文本是否包含指定内容
    /// @param str 文本
    /// @param partial 包含的内容
    static bool contains(const String& str, const String& partial);

    /// GBK编码文本转UTF8编码
    /// @param str GBK文本
    /// @return UTF8文本
    static String convertGBKToUTF8(const String& str);

    /// UTF8编码文本转GBK编码
    /// @param str UTF8文本
    /// @return GBK文本
    static String convertUTF8ToGBK(const String& str);
  private:
    StrUtil() = delete;
    StrUtil(const StrUtil&) = delete;
    StrUtil& operator=(const StrUtil&) = delete;
  };

  /// 计算多个值的哈希值
  template<typename... Args>
  size_t multiHash(const Args&... args) {
    size_t seed = 0;
    ((seed = seed ^ (std::hash<std::decay_t<Args>>{}(args) + 0x9e3779b9 + (seed << 6) + (seed >> 2))), ...);
    return seed;
  }
}

#endif //TIEC_UTIL_H
